/**
 * Copyright (c) 2017 hadlinks, All Rights Reserved.
 */
package com.bugull.farm.core.control;

import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;

import java.util.ArrayList;
import java.util.List;

/**
 * Project Name: bugu-farm-household
 * Package Name: com.bugull.farm.core.example
 * ClassName: AbstractBuguEventMananger 
 * Function: TODO ADD FUNCTION.  
 * date: 2017/10/27 21:57
 * @author songwei (songw@hadlinks.com)
 * @since JDK 1.8 
 */
public abstract class AbstractBuguEventManager<T extends AbstractBuguEventListener> {

    protected ChannelHandlerContext ctx;

    protected List<T> listeners = new ArrayList<>();

    public AbstractBuguEventManager(ChannelHandlerContext ctx) {
        this.ctx = ctx;
        AttributeKey<AbstractBuguEventManager> managerAttributeKey = AttributeKey.valueOf("manager");
        Attribute<AbstractBuguEventManager> attr = ctx.channel().attr(managerAttributeKey);
        attr.set(this);
    }

//    /**
//     * 在监听器有可能永远收不到事件触发的情况下，允许用户设置监听器超时时间，超时后监听器被自动触发，触发事件由用户指定
//     * @param ctx channel上下文对象，由于需要收发信息，所以需要将事件源绑定至上下文对象中
//     * @param timeout 超时时间
//     * @param timeUnit 超时时间对应单位
//     * @param example 用户指定的超时后触发的事件
//     */
//    public AbstractBuguEventManager(ChannelHandlerContext ctx, long timeout, TimeUnit timeUnit, AbstractBuguEvent example) {
//        this.ctx = ctx;
//        AttributeKey<List<T>> listenerAttributeKey = AttributeKey.valueOf("listener");
//        Attribute<List<T>> attr = ctx.channel().attr(listenerAttributeKey);
//        attr.set(listeners);
//        //设置监听器自动触发
//        executorService.schedule(() -> this.notifyEvent(example), timeout, timeUnit);
//    }

    /**
     * 增加事件监听器
     * @param listener
     */
    public void addListener(T listener) {
        synchronized (this) {
            if (listener != null && !listeners.contains(listener)) {
                this.listeners.add(listener);
            }
        }
    }



    /**
     * 移除事件监听器
     * @param listener
     */
    public void removeListener(T listener) {
        synchronized (this) {
            if (listeners.contains(listener)) {
                listeners.remove(listener);
//                if (ctx != null
//                        && listeners.isEmpty()
//                        && ctx.channel().hasAttr(AttributeKey.valueOf("manager"))) {
//                    ctx.channel().attr(AttributeKey.valueOf("manager")).set(null);
//                }
            }
        }
    }

    /**
     * 事件触发后通知到监听者，临时性的通知，在触发后，移除监听器
     * @param event 具体的时间类型
     * @param <P> 事件类型泛型标识
     */
    public <P extends AbstractBuguEvent> void notifyOnce(P event) {
        for (T listener : listeners) {
            this.removeListener(listener);
            listener.fireEvent(event);
        }
    }

    /**
     * 事件触发后通知到监听者，永久性的通知，在触发后，保留监听器
     * @param event 具体的时间类型
     * @param <P> 事件类型泛型标识
     */
    public <P extends AbstractBuguEvent> void notifyMulti(P event) {
        for (T listener : listeners) {
            listener.fireEvent(event);
        }
    }

}
